<?php

class Materials_Model_Material_Block implements RecursiveIterator, Countable {

	protected $_blocks = array();

    protected $_dataOrder = array();

    protected $_pointer = 0;

    protected $_count = 0;

    protected $_type = null;

	function __construct($content = null, $type = null) {
        if (null !== $content) {
            $content = (array) $content;

            foreach ($content as $key => $item) {
                $this->addBlock($key, $item);
            }
        }

        if (null !== $type) {
            $this->setType($type);
        }
	}

	/**
	 * Добавляет именованный блок контента.
	 *
	 * @throws Workset_Model_Exception
	 * @param  $name
	 * @param  $block
	 * @return Materials_Model_Material_Block
	 */
	function addBlock($name, $block) {
		if ($block instanceof Materials_Model_Material_Block) {
            $this->_updateData($name, $block);

        } elseif (is_array($block)) {

            if (isset($block['type'])) {
                $t = $block['type'];
                unset($block['type']);
            } else {
                $t = null;
            }

            if (count($block) == 1 && isInt( key($block) )) {
                
                $block = current($block);

                if (is_array($block) || null !== $t) {
                    $block = new Materials_Model_Material_Block($block, $t);
                    
                } elseif (!$block instanceof Materials_Model_Material_Block) {
                    $block = (string)$block;
                }

                $this->_updateData($name, $block);

            } else {
                $block = new Materials_Model_Material_Block($block, $t);
                $this->_updateData($name, $block);
            }

        } else {
            $this->_updateData($name, (string)$block);
        }

        return $this;
	}

    function setType($type) {
        $this->_type = (string)$type;
        return $this;
    }

    function getType() {
        return $this->_type;
    }

    protected function _updateData($key, $block) {
        if (!isset($this->_blocks[$key])) {
            $this->_blocks[$key] = $block;
        }
        
        array_push($this->_dataOrder, $key);
        $this->_count = count($this->_dataOrder);
    }

    function __sleep() {
        return array('_blocks', '_type');
    }

    function __wakeup() {
        $blocks = $this->_blocks;

        $this->_blocks = array();

        foreach ($blocks as $key => $item) {
            $this->addBlock($key, $item);
        }
    }

	/**
	 * Возвращает именованный блок контента
	 *
	 * @param  $name
	 * @return array
	 */
	function getBlock($name) {
        return isset($this->_blocks[$name]) ? $this->_blocks[$name] : null;
	}

	/**
	 * Возвращает все блоки контента
	 *
	 * @return array
	 */
	function getBlocks() {
		return $this->_blocks;
	}

	/**
	 * Возвращает блоки контента в виде многомерного массива
	 *
	 * @return array
	 */
	function toArray() {
		$result = array();

        foreach ($this as $key => $object) {
            if ($this->hasChildren()) {
                $result[$key] = $this->getChildren()->toArray();
            } elseif (is_string($object)) {
                $result[$key] = $object;
            }
        }

        return $result;
	}

	function filter($type) {
		$result = new self();

        foreach ($this as $key => $object) {
			
			if ($object instanceof self) {

				if ( (is_string($type) && $object->getType() === $type) 
						||
					 (is_array($type) && in_array($object->getType(), $type)) )
				{

					$result->addBlock($key, $object);

				} elseif ($this->hasChildren()) {

					$find = $this->getChildren()->filter($type);

					if ($find->count() > 0) {
						$find->setType($this->getChildren()->getType());
						$result->addBlock($key, $find);
					}
				}
			}
        }

        return $result;
	}
	
	function getValue( $index = null ) {
		if ( is_null( $index ) ) {
			return $this->toString();
		} else {
			$blocks = $this->getBlocks();
			return $blocks[$index];
		}
	}
	
	function toString() {
		$result = '';
		foreach ( $this->getBlocks() as $block ) {
			if ( $block instanceof self ) {
				$part = $block->toString();
			} else {
				$part = $block;
			}
			$result .= $part;
		}
		return $result;
	}
	
	function __toString() {
		return $this->toString();
	}

    function count() {
        return $this->_count;
    }

	function valid() {
        return $this->_pointer < $this->_count;
    }

    function current() {
        return $this->_blocks[ $this->_dataOrder[ $this->_pointer ] ];
    }

    function next() {
        $this->_pointer++;
    }

    function key() {
        return $this->_dataOrder[ $this->_pointer ];
    }

    function rewind() {
        $this->_pointer = 0;
    }

    function getChildren() {
        return $this->_blocks[ $this->_dataOrder[ $this->_pointer ] ];
    }

    function hasChildren() {
        return $this->_blocks[ $this->_dataOrder[ $this->_pointer ] ] instanceof Materials_Model_Material_Block;
    }

    function isEmpty() {
        return $this->_count == 0;
    }

}

?>